package rest

import (
	"context"
  "crypto/tls"
  "crypto/x509"
  "fmt"
  "github.com/grpc-ecosystem/grpc-gateway/runtime"
	"google.golang.org/grpc"
  "google.golang.org/grpc/credentials"
  "io/ioutil"
  "go.uber.org/zap"
  "net/http"
	"os"
	"os/signal"
	v1 "strtv.cn/ad-service/pkg/api/v1"
  "strtv.cn/ad-service/pkg/protocol/rest/middleware"
  "time"
	"strtv.cn/ad-service/pkg/logger"
	"strtv.cn/ad-service/bootstrap/config"
)

// RunServer runs HTTP/REST gateway
func RunServer(ctx context.Context, addr, grpcPort, httpPort string) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	mux := runtime.NewServeMux()
	credential, err := GetClientCredentials()

	if err != nil {
	  logger.Log.Fatal("credential err", zap.String("reason",err.Error()))
  }
	opts := []grpc.DialOption{grpc.WithTransportCredentials(credential)}

	if err := v1.RegisterDepartmentServiceHandlerFromEndpoint(ctx, mux, addr + ":" + grpcPort, opts); err != nil {
		logger.Log.Fatal("failed to start HTTP gateway", zap.String("reason", err.Error()))
	}

	srv := &http.Server{
		Addr: addr + ":" + httpPort,
		// add handler with middleware
		Handler: middleware.AddRequestID(
			middleware.AddLogger(logger.Log, mux)),
	}

	// graceful shutdown
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for range c {
		  // sig is a ^C, handle it
			//log.Println("shutting down gRPC server...")
      //
			//_ = srv.Shutdown(ctx)
      //
			//<-ctx.Done()
		}

		_, cancel := context.WithTimeout(ctx, 5*time.Second)
		defer cancel()

		_ = srv.Shutdown(ctx)
	}()

	logger.Log.Info("starting HTTP/REST gateway...")
	return srv.ListenAndServe()
}

func GetClientCredentials() (credentials.TransportCredentials, error) {
  cert, err := tls.LoadX509KeyPair("../../tls/client/client.pem", "../../tls/client/client.key")
  if err != nil {
    return nil, fmt.Errorf("tls.LoadX509KeyPair err: %v", err)
  }

  certPool := x509.NewCertPool()
  ca, err := ioutil.ReadFile("../../tls/ca.pem")
  if err != nil {
    return nil, fmt.Errorf("ioutil.ReadFile err: %v", err)
  }

  if ok := certPool.AppendCertsFromPEM(ca); !ok {
    return nil, fmt.Errorf("certPool.AppendCertsFromPEM err")
  }

  c := credentials.NewTLS(&tls.Config{
    Certificates: []tls.Certificate{cert},
    ServerName:   config.String("SERVICE.COMMONNAME"),
    RootCAs:      certPool,
  })
  return c, err
}
